/*
  1.创建一个生产者，两个消费者
  2.生产者0.5秒生产一个产品，并且发送条件变量广播唤醒等待的线程
  3.消费者1秒消费一个产品
  4.条件变量要配合互斥锁
*/

#include "spu.h"
#include <time.h>

/*产品结构体*/
typedef struct product{
    int num;
    struct product *next;  //指向下一个产品
}product_t;

/*定义第一个产品：链表首节点*/
product_t *head = NULL;

/*初始化互斥锁*/
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;  //使用宏定义初始化互斥锁
/*初始化条件变量*/
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;     //使用宏定义初始化条件变量

/*
  生产者线程
*/
void *thread_product(void *arg)
{
    for(;;)
    {
        //申请一个新的节点
        product_t *p = (product_t*)malloc(sizeof(product_t));
        p->num = rand()%100 + 1;  //生成 1-100 之间的随机数

        //加锁
        pthread_mutex_lock(&mutex);

        //向链表表头加节点
        p->next = head;
        head = p;
        printf("生产者：%d\n",head->num);

        //解锁
        pthread_mutex_unlock(&mutex);
        //通知所有/单个消费者
        pthread_cond_broadcast(&cond);
        
        usleep(500000);
    }
}

/*
  消费者线程1
*/
void *thread_consume01(void *arg)
{
    for(;;)
    {
        //加锁
        pthread_mutex_lock(&mutex);

        //如果没有产品则等待
        if(head->next == NULL)
          //等待被通知，如果无通知，则自解锁(通过第二个参数)，进入阻塞状态，等待被系统唤醒
          pthread_cond_wait(&cond, &mutex);
        //得到通知，开始消费
        printf("消费者1：%d\n", head->num);
        head = head->next;

        //解锁
        pthread_mutex_unlock(&mutex);
        usleep(1000000);

    }
}

/*
  消费者线程2
*/
void *thread_consume02(void *arg)
{
    for(;;)
    {
        //加锁
        pthread_mutex_lock(&mutex);

        //如果没有产品则等待
        if(head->next == NULL)
          //等待被通知，如果无通知，则自解锁(通过第二个参数)，进入阻塞状态，等待被系统唤醒
          pthread_cond_wait(&cond, &mutex);
        //得到通知，开始消费
        printf("消费者2：%d\n", head->num);
        head = head->next;

        //解锁
        pthread_mutex_unlock(&mutex);
        usleep(1000000);

    }
}

int main()
{
    srand((unsigned int)time(NULL));  //设置随机种子          
    pthread_t pro_pid, con_pid1, con_pid2;
    void *_return1,*_return2,*_return3;

    /*创建生产者线程*/
    pthread_create(&pro_pid, NULL, thread_product, NULL);
    /*创建消费者线程1*/
    pthread_create(&con_pid1, NULL, thread_consume01, NULL);
    /*创建消费者线程2*/
    pthread_create(&con_pid2, NULL, thread_consume02, NULL);


    /*等待线程结束*/
    pthread_join(pro_pid,_return1);
    pthread_join(con_pid1,_return2);
    pthread_join(con_pid2,_return3);

    /*销毁互斥量*/
    pthread_mutex_destroy(&mutex);
    /*销毁条件变量*/
    pthread_cond_destroy(&cond);
}
